import React from 'react';

/**
 * PropertyEditor class - Base class for all property editors.
 * Property editors render and edit specific property types in a DetailView.
 */
export abstract class PropertyEditor {
  private _propertyName: string;
  private _caption: string;
  private _readOnly: boolean = false;
  private _isRequired: boolean = false;
  private _validationRules: Array<{
    validate: (value: any) => { valid: boolean; error?: string };
    errorMessage: string;
  }> = [];

  /**
   * Create a new PropertyEditor
   * @param propertyName The name of the property to edit
   * @param caption Display caption for the property
   */
  constructor(propertyName: string, caption: string) {
    this._propertyName = propertyName;
    this._caption = caption;
  }

  /**
   * Get the property name
   */
  public get propertyName(): string {
    return this._propertyName;
  }

  /**
   * Get the property caption
   */
  public get caption(): string {
    return this._caption;
  }

  /**
   * Set the property caption
   */
  public set caption(value: string) {
    this._caption = value;
  }

  /**
   * Get whether this editor is read-only
   */
  public get readOnly(): boolean {
    return this._readOnly;
  }

  /**
   * Set whether this editor is read-only
   */
  public set readOnly(value: boolean) {
    this._readOnly = value;
  }

  /**
   * Get whether this property is required
   */
  public get isRequired(): boolean {
    return this._isRequired;
  }

  /**
   * Set whether this property is required
   */
  public set isRequired(value: boolean) {
    this._isRequired = value;
    if (value) {
      this.addValidationRule(
        (value) => ({
          valid: value !== null && value !== undefined && value !== '',
          error: 'This field is required'
        }),
        'Required field'
      );
    }
  }

  /**
   * Add a validation rule
   * @param rule A function that validates the value and returns { valid: boolean, error?: string }
   * @param errorMessage The error message to display when validation fails
   */
  protected addValidationRule(rule: (value: any) => { valid: boolean; error?: string }, errorMessage: string) {
    this._validationRules.push({
      validate: rule,
      errorMessage
    });
  }

  /**
   * Validate a property value
   * @param value The value to validate
   */
  protected validate(value: any): { valid: boolean; error?: string } {
    // Check required validation first
    if (this.isRequired) {
      const isEmpty = value === null || value === undefined || value === '';
      if (isEmpty) {
        return { valid: false, error: 'This field is required' };
      }
    }

    // Run all validation rules
    for (const rule of this._validationRules) {
      const result = rule.validate(value);
      if (!result.valid) {
        return { valid: false, error: result.error || rule.errorMessage };
      }
    }

    return { valid: true };
  }

  /**
   * Format a value for display
   * @param value The value to format
   */
  protected format(value: any): any {
    // Base implementation just returns the value as is
    // Subclasses can override to provide specific formatting
    return value;
  }

  /**
   * Parse a display value back to a property value
   * @param displayValue The display value to parse
   */
  protected parse(displayValue: any): any {
    // Base implementation just returns the display value as is
    // Subclasses can override to provide specific parsing
    return displayValue;
  }

  /**
   * Render this property editor - to be implemented by subclasses
   * @param value The current property value
   * @param onChange Callback to handle value changes
   */
  public render(value: any, onChange: (newValue: any) => void): {
    type: string;
    caption: string;
    value: any;
    readOnly: boolean;
    onChange: (newValue: any) => void;
    error?: string;
    [key: string]: any;
  } {
    // Validate the value
    const validation = this.validate(value);
    
    // Format the value for display
    const displayValue = this.format(value);
    
    // Create a wrapped onChange handler that parses the input
    const handleChange = (newDisplayValue: any) => {
      try {
        const newValue = this.parse(newDisplayValue);
        const validation = this.validate(newValue);
        
        if (validation.valid) {
          onChange(newValue);
        }
      } catch (error) {
        console.error(`PropertyEditor ${this.propertyName}: Error parsing value:`, error);
      }
    };
    
    return {
      type: 'unknown',
      caption: this.caption,
      value: displayValue,
      readOnly: this.readOnly,
      onChange: handleChange,
      error: validation.error,
      required: this.isRequired
    };
  }
}
